package cn.tedu.charging.order.mqtt;

import cn.tedu.charging.common.utils.JsonUtils;
import cn.tedu.charging.order.common.MqttConstants;
import cn.tedu.charging.order.dao.mapper.ChargingFailMapper;
import cn.tedu.charging.order.dao.mapper.ChargingSuccessMapper;
import cn.tedu.charging.order.pojo.dto.ChargingResultDto;
import cn.tedu.charging.order.pojo.po.ChargingFailPO;
import cn.tedu.charging.order.pojo.po.ChargingSuccessPO;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * eqmx 的消费者
 * 用来 消费 设备给emqx发送的消息
 */
@Slf4j
public class MqttConsumer implements MqttCallbackExtended {
//    @Autowired
//    ChargingSuccessMapper chargingSuccessMapper;
//    @Autowired
//    ChargingFailMapper chargingFailMapper;

    private MqttClient mqttClient;

    private MqttContext mqttContext;

    /**
     * 可以通过 构造方法 把容器中的 MqttClient 传递进来
     * MqttConsumer的变量 mqttClient 来接受
     * @param mqttClient
     */
    public MqttConsumer(MqttClient mqttClient,MqttContext mqttContext) {
        this.mqttClient = mqttClient;
        this.mqttContext = mqttContext;
    }

    /**
     * 连接成功的时候
     * 订单服务和EMQX 连接成功后，会调用 connectComplete
     * @param reconnect If true, the connection was the result of automatic reconnect.
     * @param serverURI The server URI that the connection was made to.
     */
    @Override
    public void connectComplete(boolean reconnect, String serverURI) {
        log.debug("connectComplete被调用了  表示订单服务和EMQX连接完成");
        //订单服务在和EMQX连接成功后，通过MqttClient 订阅 设备给订单发送开始充电结果的topic
        String chargingResultTopic = "/topic/charging/result";
        try {
            mqttClient.subscribe(chargingResultTopic);
            log.debug("订单服务成功订阅topic:{}",chargingResultTopic);
        } catch (MqttException e) {
            log.error("订阅topic:{}失败",chargingResultTopic,e);
        }
    }

    /**
     *  连接成功后，如果连接断开，会调用 connectionLost
     * @param cause the reason behind the loss of connection.
     */
    @Override
    public void connectionLost(Throwable cause) {
        log.error("connectionLost 被调用了，连接断开:",cause);
    }

    /**
     * 设备发送消息到一个topic
     * 如果订单服务订阅了这个topic
     * 消息就会到达这个topic
     * 当消息到达后，会调用 messageArrived
     * 设备发送的消息到达订单，这个方法会被调用
     * @param topic name of the topic on the message was published to
     * @param topic name of the topic on the message was published to
     * @param message the actual message.
     * @throws Exception
     */
    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        log.debug("消息到达订单服务:topic:{},message:{}",topic,message);
        //设备给订单发送的是一条JSON字符串，这句是把JSON字符串转换为ChargingResultDto对象，方便后续处理、使用
        // MQTT中的  {"orderNo":"666","gunId":1,"pileId":666,"result":"start_success"}
        ChargingResultDto chargingResultDto = JsonUtils.fromJson(message.toString(), ChargingResultDto.class);
        log.debug("消息到达订单服务，转化为对象:{}",chargingResultDto);
        if(chargingResultDto!=null){
            //设备返回的开始充电结果
            String result = chargingResultDto.getResult();
            //添加到常量类  MqttConstants
            if(MqttConstants.CHARGING_RESULT_SUCCESS.equals(result)){
                log.debug("charging-order 订单服务接收到设备《开始充电成功》响应");
                // 创建一个 ChargingSuccessPO 对象，用来保存成功订单记录
                ChargingSuccessPO chargingSuccessPO = new ChargingSuccessPO();
                // 将返回 结果 中的 OrderNo 订单编号 赋值给 成功订单的 billId
                chargingSuccessPO.setBillId(chargingResultDto.getOrderNo());
                // 将 ChargingResultDto 复制属性到 ChargingSuccessPO
                BeanUtils.copyProperties(chargingResultDto,chargingSuccessPO);
                // 设置订单状态为 成功  充电中  1
                chargingSuccessPO.setBillStatus(MqttConstants.ORDER_STATUS_CHARGING_PROCESS);
                log.debug("保存成功订单记录:{}",chargingSuccessPO);
                //调用ChargingBillRepository 保存成功订单记录
                Integer row = mqttContext.getChargingBillRepository().saveSuccessOrder(chargingSuccessPO);
                log.debug("保存成功订单记录:{},影响行数:{}",chargingSuccessPO,row);
                //开始充电后，不是一下就冲完的，是需要有一个过程，这个充电过程是需要时间的
                log.debug("设备会定时的同步充电进度，直到充满");
                //冲完电后，会返回一个消息给订单服务，告诉订单服务，充电完成，向用户收费
            }else if(MqttConstants.CHARGING_RESULT_FAIL.equals(result)){
                log.debug("charging-order 订单服务接收到设备《开始充电失败》响应");
                // 创建一个 ChargingFailPO 对象，用来保存失败订单记录
                ChargingFailPO chargingFailPO = new ChargingFailPO();
                // 将返回 结果 中的 OrderNo 订单编号 赋值给 失败订单的 billId
                chargingFailPO.setBillId(chargingResultDto.getOrderNo());
                // 将 ChargingResultDto 复制属性到 ChargingFailPO
                BeanUtils.copyProperties(chargingResultDto,chargingFailPO);
                //记录失败原因  设备响应：无法开始充电
                chargingFailPO.setFailDesc("设备响应：无法开始充电");
                //调用ChargingBillRepository 保存失败订单记录
                log.debug("保存失败订单记录:{}",chargingFailPO);
                Integer row = mqttContext.getChargingBillRepository().saveFailOrder(chargingFailPO);
                log.debug("保存失败订单记录:{},影响行数:{}",chargingFailPO,row);
                log.debug("修改抢的状态为故障");
                //调用DeviceFeignClient 修改抢的状态为故障
                //deviceFeignClient.updateChargingStatus(chargingResultDto.getGunId(), ChargingStatus.FAULT);
                log.debug("通知用户充电失败，请更换其他充电桩、抢");
                log.debug("可扩展业务：给用户 发送优惠卷、由于设备问题导致本次充电不成功表示歉意（非核心逻辑）");
                log.debug("通知设备管理员，检修设备");
            }else {
                log.debug("订单服务收到设备《开始充电》响应,相应结果不正确");
            }
        }
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
        log.debug("deliveryComplete 投递成功");
    }
}